Link to this headingBittorrent
How it works
- Use either a magnet link or a torrent file to get a tracker.
- Query the tracker for upto date peers
- Connect to the peers and request pieces of data.
- Send Bittorrent Handshake
- Optional: Send what pieces of data you currently have
- Send “Intrested” message to the peer
- Wait for an “Unchoke” message. This means that the peer is ready to send you data
Link to this headingMagnet URL
Example
magnet:?xt=urn:btih:PVJBBJYRFEOXDAOW4B2M4XV5K3Z75XLA&dn=debian-12.10.0-amd64-netinst.iso&xl=663748608&tr=http%3A%2F%2Fbttracker.debian.org%3A6969%2Fannounce
A magnet URL contains:
- The tracker URL
- Extra Tracker URLs
- The Torrent Name
- The number of pieces the torrent has
- The Info hash which is the unique id for the torrent
How to download using a magnet url:
- Parse the magnet url to get the information inside it.
- Query the tracker for upto date peers
- Connect to the peers and request pieces of data.
- Send Bittorrent Handshake
- Optional: Send what pieces of data you currently have
- Send “Intrested” message to the peer
- Wait for an “Unchoke” message. This means that the peer is ready to send you data
- Optional: Wait for a “bitfield” message to see what pices they have availe for you to request
- Send a “Request” message with the index and offset to download a chunk of data.
- Hash the received chunk and validate that it is the same hash as in the torrent file
- Go to 4 until all chunks are downloaded
Link to this headingTorrent Files
A torrent file contains:
- The tracker URL
- The number of pieces or blocks of data
- The file and folder names and block size of the files
- The [SHA1](/Crypto/Hash Functions/SHA1) Hashes of each block piece of data.
How to download using a torrent file:
- Parse the torrent file to get the information inside it.
- Query the tracker for upto date peers
- Connect to the peers and request pieces of data.
- Send Bittorrent Handshake
- Optional: Send what pieces of data you currently have
- Send “Intrested” message to the peer
- Wait for an “Unchoke” message. This means that the peer is ready to send you data
- Optional: Wait for a “bitfield” message to see what pices they have availe for you to request
- Send a “Request” message with the index and offset to download a chunk of data.
- Hash the received chunk and validate that it is the same hash as in the torrent file
- Go to 4 until all chunks are downloaded
Parsing a Torrent File:
# Integer: i<integer>e
=
=
return , + 1
# List: l<items>e
+= 1
=
, =
return , + 1
# Dictionary: d<key><value>e
+= 1
=
, =
, =
=
return , + 1
# String: <length>:<data>
=
=
= + 1
= +
return ,
, =
return
=
=
=
=
#Parse the pieces to an array of hex strings
=
=
=
#{b'announce': b'http://bttracker.debian.org:6969/announce', b'comment': b'Debian CD from cdimage.debian.org', b'created by': b'mktorrent 1.1', b'creation date': 1742039925, b'info': {b'length': 663748608, b'name': b'debian-12.10.0-amd64-netinst.iso', b'piece length': 262144, b'pieces': ['4e6a88778c00584c9d1494f3504f885fe6354569', 'c4405c23fab73c6a05e25b5306612d6d35510afd', '9915ee1573f64c676f82a2f40847152243544cfe', '976e0a51e8d6aadeb6657a6c7a8689f69e1d0e15', 'f324bfbf2fe575e6bc0c451d91588ceb081207b1', 'e61a61a1fb2c53b33395671a22cae004371654d2', 'dc2692544e67dc3772ccb0bb32ffb8007c33b8a8', '09835cee94b5674152c4ae389ddf8db7929d093e', 'cd1ed06cffea2c85d2789c879765e03c00791ce2', '3891fafac9a153f9d1935e48ecf67294025dbfa2', '9b10b44b715ed46a76e5fe3f6b9fe4be4930e05f', 'a4c0a93365c8b1c9cdecea42b592b87caf7d5560', '9cdbaffada32e10f79bca03bf532080749bed39b', 'abd9164db72567f3116d39ae75208e8f72f88755', '2c16b79182b43aa06091c7aa1bf3d69b48bec8af', '46edba3c5e5afc43a2cb4665387a615105db7281',
#...
NOTE: The Info hash is used to uniquely identify the torrent. This is just the [sha1](/Crypto/Hash Functions/SHA1) hash of the torrent_dict['info'] data.
Link to this headingTrackers
Trackers only have a list of the ipv4 and ipv6 peers that you can connect to.
Get Tracker Information:
# Integer: i<integer>e
=
=
return , + 1
# List: l<items>e
+= 1
=
, =
return , + 1
# Dictionary: d<key><value>e
+= 1
=
, =
, =
=
return , + 1
# String: <length>:<data>
=
=
= + 1
= +
return ,
, =
return
=
=
=
=
=
return
=
=
# Parse the tracker URL
=
# Build the GET request
=
=
=
= # VERY IMPORTANT: safe="%"
= f
# Make the connection
=
=
=
=
=
#Parse the peers into a ip:port format
=
=
=
= +
=
= +
#Tracker replied with 472 bytes
#Decoded data: {b'interval': 900, b'peers': b'\xc3\x80\xac:\xc8\xd5-V\xd2\xa4\xc6\xbfS\x94\xf5\xba\xc8\xd6\x96\x88\xa0w\xda\x91GOP\x84\x1a\xe1\x02"a\x90\x1a\xe1\xb9\x94\x01N\x9c3W4h\x89\xc8\xd5.\xbf\xe6\xf3p\xda\x9b]\xc0\x89\x1a\xe1r#\xf5\x96\x1dL\x18;\x9c\x85\xd2\x14\xb9\x95[\r\xc7Nl8J\xf7i\xffk\xc0)xA\xf1\x17\x80 f\xc4\xed\x87\x17\xaa\xab\xc8\xd5\x88>!onV\xbc\x06\xb08\xb5W^i~\xf3\xc8\xd5\x18\xcf\xa8\xf3\xf3\x8c\x95\x16YI\x1a\xe1\xa1\x1d\xdf\xf5BU\xc1mx\xab\xfbG\x18\xf7D\x82|{N.0\x0b\xc3P\xa2\xfd\x14\xc9\x18\xcaW\x1bR\x99\xc8\xd5\x05\x98\x82)g%Yi\xca\x86\xca\xc6\xc1\xc0$\n\xa5\x98N8\xf8L\xd9\x0fW\x9c\x8e\xca\xc8\xd5V}\xe0\x8f\x8c\x12QgmT\x07K\x95X\x1b\x93\x145\xc6\x10\x87\xa1\xe8mO\x7f\x860\xc3PRA\xa0\x0f\xd3\xe2', b'peers6': b" \x01\t\x9a$\xedM\x00\x9ek\x00\xff\xfezD;\xc8\xd5*\t^A\x0e\xb0\x03\xf0H?\xaf\xa4~\xe7\x11\xae\xc8\xd5(\x04\x01L;\xb6\x15y\xfb\xb6\x92\xe4\x8do\x94\x90\xe3\xd0 \x01\xb0\x11@\x06x&\x00\x00\x00\x00\x00\x00\x00\n\x1dL*\x01\x02a\x08\xfd\x86\x00+\xe3\xc4Ib\x87\x83\xc7YI \x01LL#)\xfa\x00\n._\xff\xfe\x01\x18>\xf3D \x01LL\x1e\xa0P\x00\x02\xe0L\xff\xfe\x14c\x8f\xb5W \x01LL\x1e\xa0P\x00\x0c'IGh\x90]L\xb5W*\x03\xa9\xc0\xf2\x00\x00\x00\x88S` \x93\xa8\x1ba\xa5\x98 \x03\x00\xea\x0f\x00I\x00.\xf0]\xff\xfe\xdc\xffc\xc8\xd5*\x02/\n\xe1\x04\xd1\x00P1\xb1\xff\xfe&\xba\xb0\x8c\x12"}
#Peer: 195.128.172.58:51413
#...
Link to this headingFull single threaded implementation
# Integer: i<integer>e
=
=
return , + 1
# List: l<items>e
+= 1
=
, =
return , + 1
# Dictionary: d<key><value>e
+= 1
=
, =
, =
=
return , + 1
# String: <length>:<data>
=
=
= + 1
= +
return ,
, =
return
= None
=
=
=
= None
= 0
= 0
= 2**14
=
=
# Assume it's a torrent file
# Parse the pieces to an array of hex strings
return
=
=
=
=
=
return
=
=
=
=
return
=
=
# Parse the pieces to an array of hex strings
=
=
=
=
=
=
=
return
= 19
= b
= b * 8
=
return
=
= # VERY IMPORTANT: safe="%"
= f
# Make the connection
=
=
=
#print(f"Decoded data: {bdecode(data)}")
=
=
#Parse the peers into a ip:port format
=
=
=
= +
#print(f"Peer: {ip}:{port}")
=
= +
#print(f"Peer: {ip}:{port}")
# Read 4 bytes (message length)
=
=
return None, b # keep-alive message
# Read the full message
=
=
=
return ,
= b
=
return None
+=
return
= b * # Assuming no pieces are available
=
# 1. Send handshake
=
# 2. Receive handshake
=
# 3. Send 'bitfield' message (ID = 5)
#Not reqired because we dont have any pieces yet
#self.send_message(sock, "bitfield")
# 3. Send 4byte length + ID for 'interested' (ID = 2)
# 4. Wait for 'unchoke' (ID = 1) for 30 seconds
=
, =
break
continue
# 5. Request and receive piece(s)
= 0
# Send a request for the first block of the piece
# Receive 'piece' message (ID = 7)
, =
continue
=
=
=
= + 1
break # For now, download only one piece
=
# Connect to the first peer and download a piece
, =
, =
Link to this headingDistributed Hash Tables (DHT)
DHT is a way to look for more Peers. Instead of using a centralized server to look for peers like with an announce server. You can ask peers if they know other peers to connect to. Doing so recursively until you make a list of all of the peers that are available to download pieces from.
=
= 2
= 3
return
=
=
=
# hex
return
# base32
return
=
=
=
=
return
return
return
=
=
= # (ip, port)
= # (ip, port)
=
return
=
continue
=
, =
=
=
=
=
=
continue
=
=
, =
=
=
=
=
=